/*******************************************************************************
 * Copyright (c) 2023. 山东新北洋信息技术股份有限公司 保留所有权利。
 *
 ******************************************************************************/

/*
 * 版权所有 2009-2022山东新北洋信息技术股份有限公司 保留所有权利。
 */
package online.xuping.thousandsOfWorlds.common.importexcel.strategy;

import com.alibaba.excel.EasyExcelFactory;
import online.xuping.thousandsOfWorlds.common.constants.Constants;
import online.xuping.thousandsOfWorlds.common.exception.BusinessRuntimeException;
import online.xuping.thousandsOfWorlds.common.importexcel.ExcelImportListener;
import online.xuping.thousandsOfWorlds.common.importexcel.domain.ImportErrorVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamSource;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Slf4j
public abstract class AbstractExcelImport<T extends ImportErrorVO> {

    /**
     * 解决线程并发问题，每个线程单独持有自己的属性
     **/
    private final ThreadLocal<ExcelImportListener<T>> excelImportListener = new ThreadLocal<>();

    /**
     * 获取导入实体类对象
     *
     * @return java.lang.Class
     * @date 2022/9/26 10:04:00
     * @author wangbin
     **/
    public abstract Class getVOClass();

    /**
     * 设置默认最大值为1000
     *
     * @return {@link Integer } 返回最大行数
     */
    public Integer getMaxRow() {
        return Constants.ONE_THOUSAND_INT;
    }


    /**
     * 导入Excel默认实现
     *
     * @param file : 传入文件
     * @author yujian
     * @date 2022/8/31 10:39
     **/
    public void importExcel(MultipartFile file) throws IOException {
        excelImport(file);
    }

    /**
     * 获取错误数据列表
     *
     * @return {@link List } 返回错误列表信息
     * @author yujian
     * @date 2022/8/31 10:39
     **/
    public List getErrorList() {
        return excelImportListener.get().getErrorList();
    }

    /**
     * 获取导入正确的列表
     *
     * @return {@link List } 返回错误列表信息
     * @author yujian
     * @date 2022/8/31 10:40
     **/
    public List getCorrectList() {
        return excelImportListener.get().getCorrectList();
    }

    /**
     * 校验表头信息,传入校验的类名
     *
     * @author yujian
     * @date 2022/8/24 13:50
     **/
    public void setClassType() {
        excelImportListener.set(new ExcelImportListener<>(getVOClass()));
    }

    /**
     * 设置导入的行数限制
     *
     * @author dongyinggang
     * @date 2023/5/30 17:52
     **/
    public void setMaxRow(Integer maxRow) {
        excelImportListener.get().setMaxRowCount(maxRow);
    }


    /**
     * 获取导入表头错误信息
     *
     * @return {@link String } 返回表头检验错误信息
     * @author yujian
     * @date 2022/8/27 14:12
     **/
    public List<String> getHeadError() {
        return excelImportListener.get().getHeadError();
    }

    /**
     * 对列表执行操作
     *
     * @param : 传入参数
     * @return {@link Object } 返回结果信息
     * @author yujian
     * @date 2022/8/27 10:46
     **/
    public abstract Object dealList(List errorList, List correctList);


    /**
     * 表头校验结果信息
     *
     * @param headError : 传入表头校验结果
     * @return {@link String } 返回表头校验信息
     * @author yujian
     * @date 2022/8/27 14:14
     **/
    public void checkHead(List<String> headError) {
        //判断表头是否为空
        if (CollectionUtils.isEmpty(excelImportListener.get().getGlobalHeadMap())) {
            log.info("表头为空");
            throw new BusinessRuntimeException("表头为空,请下载模板填写数据");
        }

        if (CollectionUtils.isEmpty(headError)) {
            //若异常list为空
            log.info("表头校验通过");
            return;
        }
        //如果有异常信息，说明校验信息不通过，构建校验结果信息
        StringBuilder errorMessage = new StringBuilder();
        for (int i = 0; i < headError.size(); i++) {
            errorMessage.append(headError.get(i)).append("<br />");
            //超过五行，就不再输出到前端进行提示了
            if (i == Constants.FOUR_INT) {
                errorMessage.append("...(还有").append(headError.size() - i).append("条未展示),");
                break;
            }
        }
        errorMessage.append("请下载模板进行校对!");
        throw new BusinessRuntimeException("表头校验失败，错误信息为：<br />" + errorMessage);

    }


    /**
     * 执行excel导入
     *
     * @param file : 传入导入的文件
     * @author yujian
     * @date 2022/8/27 10:57
     **/
    public void excelImport(InputStreamSource file) throws IOException {
        //声明一个新的监听
        setClassType();
        //设置最大读取行数
        setMaxRow(getMaxRow());
        //读取文件
        InputStream fileInput = file.getInputStream();
        //easyExcel读取数据 ignoreEmptyRow 是关闭忽略空行，保证表头校验始终执行
        EasyExcelFactory.read(fileInput, getVOClass(), excelImportListener.get())
                .ignoreEmptyRow(false)
                .headRowNumber(1)
                .sheet().doRead();
        //处理表头校验结果
        checkHead(getHeadError());
        //对正确的数据和错误的数据的处理
        dealList(excelImportListener.get().getErrorList(), excelImportListener.get().getCorrectList());
    }
}
